<?php
/**
 * Application bootstrap. Include this file then call Application::run().
 *
 * Alternate usage of the Mz_Bootstrapper class; subclassing it and registering
 * itself during init.
 *
 * @author     Mon Zafra <monzee at gmail>
 * @copyright  (c)2009 Mon Zafra
 * @category   Mz
 * @package    demo
 * @license    http://mz-project.googlecode.com/svn/trunk/LICENSE    MIT License
 * @version    SVN: $Id: Application.php 11 2009-02-28 13:37:10Z monzee $
 */

// this stuff needs to be outside because Application can't be isntantiated
// if the autoloader isn't enabled and/or the paths are wrong.

$old_paths = explode(PATH_SEPARATOR, get_include_path());
$paths_to_prepend = array('../lib');
$paths_to_append = array('../app/models');
$new_paths = array_merge($paths_to_prepend, $old_paths, $paths_to_append);

$new_paths = array_map('realpath', array_unique($new_paths));
set_include_path(implode(PATH_SEPARATOR, $new_paths));

require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

class Application extends Mz_Bootstrapper
{
    const DEVELOPMENT = 'dev';
    const PRODUCTION = 'production';
    const TESTING = 'testing';

    static protected $_basePath;
    static protected $_config;
    protected $_env = self::DEVELOPMENT;
    protected $_initialized = false;

    /**
     * ZCF instance
     *
     * @var Zend_Controller_Front
     */
    protected $_front;

    /**
     * Setup application environment, registers self to ZCF
     *
     * @param string $env
     * @return void
     */
    public function init($env = null)
    {
        if ($this->_initialized) {
            return;
        }

        if (null === $env) {
            $env = $this->_env;
        } else {
            $this->_env = $env;
        }

        if (self::PRODUCTION == $env) {
            error_reporting(0);
            ini_set('display_errors', 0);
        } else {
            error_reporting(E_ALL|E_STRICT);
            ini_set('display_errors', 1);
        }

        $this->_methods = array(
            'setupRoutes', 'setupDatabase',
            'setupControllers', 'setupView', 'setupPlugins',
        );

        $this->getFront()
             ->throwExceptions(self::PRODUCTION != $env)
             ->registerPlugin($this);

        $this->_initialized = true;
    }

    /**
     * Custom routes
     */
    public function setupRoutes()
    {

    }

    /**
     * Default ZDT adapter
     */
    public function setupDatabase()
    {
        if (null === Zend_Db_Table_Abstract::getDefaultAdapter()) {
            $db_conf = $this->getConfig($this->_env)->db->toArray();
            $driver = array_shift($db_conf);
            $params = array_shift($db_conf);

            $adapter = Zend_Db::factory($driver, $params);
            Zend_Db_Table_Abstract::setDefaultAdapter($adapter);
        }
    }

    /**
     * Controller stuff
     */
    public function setupControllers()
    {
        $front = $this->getFront();
        $front->setControllerDirectory($this->pathTo('controllers'))
              ->addModuleDirectory($this->pathTo('modules'));

        Zend_Controller_Action_HelperBroker::addPath(
            $this->pathTo('controllers/helpers'), 'Action');

        Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector')
            ->setPrependBase(false);
    }

    /**
     * View, view renderer, layout
     */
    public function setupView()
    {
        $view = new Zend_View();
        $view->addHelperPath($this->pathTo('views/helpers'), 'View')
             ->doctype(Zend_View_Helper_Doctype::XHTML1_TRANSITIONAL);

        $renderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
        $renderer->setView($view);

        Zend_Layout::startMvc(array('layoutPath' => $this->pathTo('layouts')));
    }

    /**
     * Register front controller plugins here.
     */
    public function setupPlugins()
    {
        $this->getFront()->registerPlugin(new Mz_Module_Initializer());
    }

    /**
     * Dispatches ZCF.
     *
     * @return mixed
     */
    public function dispatch()
    {
        return $this->getFront()->dispatch();
    }

    /**
     * Returns the ZCF singleton
     *
     * @return Zend_Controller_Front
     */
    public function getFront()
    {
        if (null === $this->_front) {
            $this->_front = Zend_Controller_Front::getInstance();
        }
        return $this->_front;
    }

    /**
     * Set front controller
     *
     * @param Zend_Controller_Front $front
     */
    public function setFront($front)
    {
        $this->_front = $front;
    }

    /**
     * Returns the whole config or a key
     *
     * @param string $key
     * @param mixed  $config Zend_Config instance or config filename (ini)
     * @return Zend_Config
     */
    static public function getConfig($key = null, $config = 'config.ini')
    {
        if (null === self::$_config) {
            if ($config instanceof Zend_Config) {
                self::$_config = $config;
            } else {
                $file = self::pathTo($config);
                self::$_config = new Zend_Config_Ini($file);
            }
        }

        if (null === $key) {
            return self::$_config;
        } else {
            return self::$_config->$key;
        }
    }

    /**
     * Returns a path relative to the directory where this file resides.
     *
     * @param string $path
     * @return string
     */
    static public function pathTo($path = null)
    {
        if (null === self::$_basePath) {
            self::$_basePath = realpath(dirname(__FILE__));
        }

        $ret = self::$_basePath;
        if (!empty($path)) {
            $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, trim($path, '/\\'));
            $ret .= DIRECTORY_SEPARATOR . $path;
        }

        return $ret;
    }

    /**
     * Instantiate app, initialize, run, return
     *
     * @param string      $env
     * @param Application $app Pass a second variable if you want a reference
     *                         to the instantiated app
     * @return mixed Returns response if ZCF is set to return it
     */
    static public function run($env = null, &$app = null)
    {
        $app = new self();
        $app->init($env);
        return $app->dispatch();
    }

}
